﻿using Microsoft.Xna.Framework.Graphics;
using Phoenix.Xna.Framework.ContentPipeline;

namespace Phoenix.Xna.Framework.Graphics
{
    public class HeightMap
    {
        private float[,] _heightStore;

        public float this[int x, int z]
        {
            get { return _heightStore[x, z]; }
            set { _heightStore[x, z] = value; }
        }
        public int Width { get; private set; }
        public int Height { get; private set; }

        public HeightMap(IContentService content, string heightMapAsset, int? smoothingPasses)
        {
            GenerateHeightStore(content, heightMapAsset);

            if (smoothingPasses != null && smoothingPasses.Value > 0)
            {
                SmoothHeightMap(smoothingPasses.Value);
            }
        }

        private void GenerateHeightStore(IContentService content, string heightMapAsset)
        {
            Texture2D texture = content.Load<Texture2D>(heightMapAsset);
            Width = texture.Width;
            Height = texture.Height;
            _heightStore = new float[Width, Height];
            Color[] heightMapColors = new Color[texture.Width * texture.Height];
            texture.GetData(heightMapColors);

            for (int x = 0; x < texture.Width; x++)
            {
                for (int y = 0; y < texture.Height; y++)
                {
                    _heightStore[x, y] = heightMapColors[x + y * texture.Width].R * 32f;
                }
            }

            content.Release(heightMapAsset);
        }

        private void SmoothHeightMap(int numberOfPasses)
        {
            float[,] newHeightStore;

            while (numberOfPasses > 0)
            {
                numberOfPasses--;
                newHeightStore = new float[Width, Height];

                for (int x = 0; x < Width; x++)
                {
                    for (int y = 0; y < Height; y++)
                    {
                        int adjacentSections = 0;
                        float sectionsTotal = 0.0f;

                        if ((x - 1) > 0)
                        {
                            sectionsTotal += _heightStore[x - 1, y];
                            adjacentSections++;

                            if ((y - 1) > 0)
                            {
                                sectionsTotal += _heightStore[x - 1, y - 1];
                                adjacentSections++;
                            }

                            if ((y + 1) < Height)
                            {
                                sectionsTotal += _heightStore[x - 1, y + 1];
                                adjacentSections++;
                            }
                        }

                        if ((x + 1) < Width)
                        {
                            sectionsTotal += _heightStore[x + 1, y];
                            adjacentSections++;

                            if ((y - 1) > 0)
                            {
                                sectionsTotal += _heightStore[x + 1, y - 1];
                                adjacentSections++;
                            }

                            if ((y + 1) < Height)
                            {
                                sectionsTotal += _heightStore[x + 1, y + 1];
                                adjacentSections++;
                            }
                        }

                        if ((y - 1) > 0)
                        {
                            sectionsTotal += _heightStore[x, y - 1];
                            adjacentSections++;
                        }

                        if ((y + 1) < Height)
                        {
                            sectionsTotal += _heightStore[x, y + 1];
                            adjacentSections++;
                        }

                        newHeightStore[x, y] = (_heightStore[x, y] + (sectionsTotal / adjacentSections)) * 0.5f;
                    }
                }

                _heightStore = newHeightStore;
            }
        }
    }
}
